﻿
using Autodesk.AutoCAD.Colors;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using System.Xml.Linq;
using XS.Tunnel.Cad.SteelBracing.Component.SteelShotcrete;
using XS.Tunnel.Cad.SteelBracing.Component.SteelShotcrete.GrilleComponent;
using XS.Tunnel.Cad.SteelBracing.Component.SteelShotcrete.UniversalBeamComponent;
using XS.Tunnel.Cad.SteelBracing.Infrastructure.Helper;
using static Autodesk.AutoCAD.Internal.WSUtils;

namespace XS.Tunnel.Cad.SteelBracing.Infrastructure.Extensions
{
    public static class CadExtensions
    {


        /// <summary>
        /// 颜色转换
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static Color ToColor(this string value)
        {
            if (value?.StartsWith("#") == true)
            {
                var hexColor = value.Substring(1);
                var red = hexColor.Substring(0, 2);
                var green = hexColor.Substring(2, 2);
                var blue = hexColor.Substring(4, 2);
                return Color.FromRgb(Convert.ToByte(red, 16), Convert.ToByte(green, 16), Convert.ToByte(blue, 16));
            }
            else
            {
                return null;
            }
        }

        public static Point2d To2d(this Point3d point)
        {
            return new Point2d(point.X,point.Y);
        }

        public static Point3d To3d(this Point2d point)
        {
            return new Point3d(point.X, point.Y,0);
        }

        /// <summary>
        /// 分割
        /// </summary>
        /// <param name="curve"></param>
        /// <param name="l"></param>
        /// <returns></returns>
        public static Curve Split(this Curve curve,double l,bool isleft=false)
        {
            Point3d point = curve.GetPointAtDist(l);
            var list= curve.GetSplitCurves(new Point3dCollection { point}).Cast<Curve>().ToList();
            if (list != null)
            {
                if (isleft)
                {
                    return list[1] as Curve;
                }
                else
                {
                    return list[0] as Curve;
                }
            }
            return null;
        }
        public static Curve Split(this Curve curve,Point3d start,Point3d end)
        {
            var list = curve.GetSplitCurves(new Point3dCollection { start,end }).Cast<Curve>().ToList();
            if (list != null)
            {
                return list[1];
            }
            return null;
        }
        public static Curve Split(this Curve curve, Point3d p, bool isleft = false)
        {
            var l = curve.GetDistAtPoint(p);
            return curve.Split(l,isleft);
        }

        public static TupleExt<Curve,Curve> Split(this Curve curve, Point3d point)
        {
            var list = curve.GetSplitCurves(new Point3dCollection { point }).Cast<Curve>().ToList();
            if (list != null)
            {
                return TupleExt.Create(list[0], list[1]);
            }
            return null;
        }
        
        /// <summary>
        /// 分割 根据2个点分割取中间的
        /// </summary>
        /// <param name="curve"></param>
        /// <param name="l"></param>
        /// <returns></returns>
        public static Curve Split(this Curve curve, double l, double l2)
        {
            Point3d point1 = curve.GetPointAtDist(l);
            Point3d point2 = curve.GetPointAtDist(l2);

            var list = curve.GetSplitCurves(new Point3dCollection { point1,point2 }).Cast<Curve>().ToList();
            if (list != null)
            {
                return list[1];
            }
            return null;
        }
        /// <summary>
        /// 分割弧
        /// </summary>
        /// <param name="arc"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static List<Curve> ArcSplit(this Curve arc, int n)
        {
            var lenght = arc.GetLength();
            var avgLenght = lenght / n;
            double accumulate = avgLenght;
            var p = new Point3dCollection();
            while (accumulate<lenght)
            { 
                var point= arc.GetPointAtDist(accumulate);
                p.Add(point);
                accumulate += avgLenght;
            }
            var listSubsection = arc.GetSplitCurves(p).Cast<Curve>().ToList();
            var list= new List<Curve>();
            foreach (var item in listSubsection)
            {
                list.Add(item as Curve);
            }
            return list;
        }

        /// <summary>
        /// 逆时针
        /// </summary>
        /// <param name="arc"></param>
        /// <param name="l"></param>
        /// <param name="isIncludeStart"></param>
        /// <returns></returns>
        public static List<Curve> AnticlockwiseArcSplit(this Curve arc, double l,bool isIncludeStart=true,bool isIgnoreL=true)
        {
            var lenght = arc.GetLength();
            double countLenght = isIncludeStart?0:l;
            var p = new Point3dCollection();
            while (countLenght <= lenght)
            {
                var point = arc.GetPointAtDist(countLenght);
                p.Add(point);
                countLenght += l;
            }
            var listSubsection = arc.GetSplitCurves(p).Cast<Curve>().ToList();
            var list = new List<Curve>();
            foreach (var item in listSubsection)
            {
                if (isIgnoreL && item.GetLength() + 0.001 < l)
                {
                    break;
                }
                list.Add(item);
            }
            return list;
        }
        /// <summary>
        /// 顺时针
        /// </summary>
        /// <param name="arc"></param>
        /// <param name="l"></param>
        /// <param name="isIncludeStart"></param>
        /// <returns></returns>

        public static List<Curve> ClockwiseArcSplit(this Curve arc, double l, bool isIncludeStart = true)
        {
            var lenght = arc.GetLength();
            var countLenght =l;
            var p = new Point3dCollection();
            var Plist = new List<Point3d>();
            while (countLenght <=lenght)
            {
                var point = arc.GetPointAtDist( lenght-countLenght);
                Plist.Add(point);
                countLenght += l;
            }
            if (Plist.Count <= 0)
            {
                throw XSException.Oh("斜向钢筋长度大于了弧分割的长度");
            }
            Plist.Reverse();
            foreach (var item in Plist)
            {
                p.Add(item);
            }
            var listSubsection = arc.GetSplitCurves(p).Cast<Curve>().ToList();
            var list = new List<Curve>();
            foreach (var item in listSubsection)
            {
                list.Add(item);
            }
            return list;
        }





        /// <summary>
        /// 根据角度获取坐标
        /// </summary>
        /// <param name="value"></param>
        /// <param name="degrees"></param>
        /// <returns></returns>
        public static Point3d? GetByDegrees(this List<ISysPoint> value,double degrees)
        {
            foreach (var item in value)
            {
                if (item is ArcPoint)
                { 
                    var arc= (ArcPoint)item;
                    if (arc.StartAngle <= degrees && degrees <= arc.EndAngle  )
                    {
                        //说明在这个弧上
                        return arc.GetByDegreePoint(degrees);
                    }
                }

            }

            return null;
        }

        /// <summary>
        /// 根据角度求出弧上任意一点
        /// </summary>
        /// <param name="sysPoint"></param>
        /// <param name="degree"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static Point3d? GetByDegreePoint(this ISysPoint sysPoint, double degree)
        {
            if (sysPoint.IsArc())
            {
                var arc = sysPoint as ArcPoint;

                // 度数不在弧上
                if (arc.StartAngle > degree || degree > arc.EndAngle)
                {
                    return null;
                }

                var a =degree;
                var x = arc.OX + arc.R * Math.Cos(a.DegreeToAngle());
                var y = arc.OY + arc.R * Math.Sin(a.DegreeToAngle());
                return new Point3d(x, y, 0);
            }

            return null;
        }


        /// <summary>
        /// 凸度计算
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static double Bulge(this double value)
        { 
            return Math.Tan(value/4);
        }

        /// <summary>
        /// 曲线长度
        /// </summary>
        /// <param name="curve">曲线</param>
        /// <returns></returns>
        public static double GetLength(this Curve curve)
        {
            return curve.GetDistanceAtParameter(curve.EndParam);
        }





        /// <summary>
        /// 角度转换弧度
        /// </summary>
        /// <param name="degree">角度值</param>
        /// <returns>弧度</returns>
        public static double DegreeToAngle(this double degree)
        {
            return degree * Math.PI / 180;
        }
        /// <summary>
        /// 弧度转换角度
        /// </summary>
        /// <param name="angle">弧度值</param>
        /// <returns>角度</returns>
        public static double AngleToDegree(this double angle)
        {
            return angle * 180 / Math.PI;
        }
        /// <summary>
        /// 判断三点是否在同一条直线上
        /// </summary>
        /// <param name="firstPoint">第一个点</param>
        /// <param name="secondPoint">第二个点</param>
        /// <param name="thirdPoint">第三个点</param>
        /// <returns></returns>
        public static bool IsOnOneLine(this Point3d firstPoint, Point3d secondPoint, Point3d thirdPoint)
        {
            Vector3d v21 = secondPoint.GetVectorTo(firstPoint);
            Vector3d v23 = secondPoint.GetVectorTo(thirdPoint);
            if (v21.GetAngleTo(v23) == 0 || v21.GetAngleTo(v23) == Math.PI)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 获取两点成直线到X轴之间的角度（有正负）
        /// </summary>
        /// <param name="startPoint"></param>
        /// <param name="endPoint"></param>
        /// <returns></returns>
        public static double GetAngleToXAxis(this Point3d startPoint, Point3d endPoint)
        {
            //声明一个与X轴平行的向量
            Vector3d temp = new Vector3d(1, 0, 0);
            //获取起点到终点的向量
            Vector3d VsToe = startPoint.GetVectorTo(endPoint);
            return VsToe.Y > 0 ? temp.GetAngleTo(VsToe) : -temp.GetAngleTo(VsToe);
        }
        /// <summary>
        /// 获取两点之间的距离
        /// </summary>
        /// <param name="point1"></param>
        /// <param name="point2"></param>
        /// <returns></returns>
        public static double GetDistanceBetweenTwoPoint(this Point3d point1, Point3d point2)
        {
            return Math.Sqrt((point1.X - point2.X) * (point1.X - point2.X) + (point1.Y - point2.Y) * (point1.Y - point2.Y) + (point1.Z - point2.Z) * (point1.Z - point2.Z));

        }
        /// <summary>
        /// 获取两点的中心点
        /// </summary>
        /// <param name="Point1">第一个点</param>
        /// <param name="point2">第二个点</param>
        /// <returns>中心点</returns>
        public static Point3d GetCenterPointBetweenTwoPoint(this Point3d Point1, Point3d point2)
        {
            return new Point3d((Point1.X + point2.X) / 2, (Point1.Y + point2.Y) / 2, (Point1.Z + point2.Z) / 2);
        }

        /// <summary>
        /// 延长直线，
        /// </summary>
        /// <param name="line"></param>
        /// <param name="l"></param>
        /// <returns></returns>
        public static Line ToStartLengthen(this Line line, double l)
        {
          
            var vt=line.Delta.GetNormal();
            return new Line(line.StartPoint,line.StartPoint.Add(vt*l));
        }

        /// <summary>
        /// 延长直线，
        /// </summary>
        /// <param name="line"></param>
        /// <param name="l"></param>
        /// <returns></returns>
        public static Line ToEndLengthen(this Line line, double l)
        {
            var vt = line.Delta.GetNormal();
            return new Line(line.EndPoint, line.EndPoint.Add(vt * -l));
        }

        /// <summary>
        /// 向两侧延长
        /// </summary>
        /// <param name="line">从左向右，从上向下</param>
        /// <param name="l"></param>
        /// <returns></returns>
        public static Line ToBothSidesLengthen(this Line line, double l)
        {
            var vt = line.Delta.GetNormal();
            var start = line.StartPoint.Add(vt * -l);
            var end=line.EndPoint.Add(vt * l); 

            return new Line(start,end);
        }

        /// <summary>
        /// 两侧延长垂线
        /// </summary>
        /// <param name="line"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static Line ToBothSidesLengthen(this Curve line, Point3d point,double l)
        {
            var q = line.GetFirstDerivative(point);
            var vt = q.GetPerpendicularVector().GetNormal();
            var start= point.Add(vt * l);
            var end= point.Add(vt * -l);
            return new Line(start,end);
        }





        /// <summary>
        /// 曲线上2点的距离
        /// </summary>
        /// <param name="curve"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public static double CurveLenght(this Curve curve, Point3d start,Point3d end)
        {
            var startLenght= curve.GetDistAtPoint(start);
            var endLenght = curve.GetDistAtPoint(end);
            return endLenght-startLenght;
        }

        /// <summary>
        /// 求交点
        /// </summary>
        /// <param name="curve"></param>
        /// <param name="curve1"></param>
        /// <param name="intersect"></param>
        /// <returns></returns>
        public static Point3d IntersectPoint(this Curve curve, Curve curve1, Intersect intersect= Intersect.ExtendThis)
        {
            Point3dCollection listPoint = new Point3dCollection();//交点集合
            curve.IntersectWith(curve1, intersect, listPoint, 0, 0);
            if (listPoint.Count <= 0 )
            {
                throw XSException.Oh("仰拱与边墙未相交");
            }
            return listPoint[0];
        }

        /// <summary>
        /// 反转
        /// </summary>
        /// <param name="curve"></param>
        /// <returns></returns>
        public static Curve Reversal(this Curve curve)
        {
            if (curve is Line)
            {
                return new Line(curve.EndPoint, curve.StartPoint);
            }
            else if (curve is Arc)
            {
                var arc = curve as Arc;
                return new Arc(arc.Center, arc.Radius, arc.EndAngle, arc.StartAngle);
            }
            else if (curve is Polyline)
            {
                throw XSException.Oh("不支持多段线反向");

                //var poly = curve as Polyline;
                ////  2008 是不支持这个吊方法的
                //poly.ReverseCurve();
                //return poly;
            }
            else
            {
                return null;
            }

        }


        /// <summary>
        /// 平移
        /// </summary>
        /// <param name="curve"></param>
        /// <param name="l">移动距离</param>
        /// <returns></returns>
        public static Curve LineMove(this Line curve, double l)
        {
            var top = curve.VerticalLine(curve.StartPoint, l);
            var bottom = curve.VerticalLine(curve.EndPoint, l);
            return new Line(top.EndPoint, bottom.EndPoint);

        }



        /// <summary>
        /// 垂线
        /// </summary>
        /// <param name="curve"></param>
        /// <returns></returns>
        public static Line VerticalLine(this Curve curve,Point3d point,double l)
        {
            Vector3d curVector = curve.GetFirstDerivative(point);
            Vector3d curPervector = curVector.GetPerpendicularVector();
            curPervector = curPervector.GetNormal();
            return new Line(point, point.Subtract(curPervector *l));
        }

        /// <summary>
        /// 根据开始结束角度获取弧
        /// </summary>
        /// <param name="arc"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <returns></returns>
        public static Split3ArcModel GetByDegreeArc( this List<ISysPoint> arc, double start,double end)
        {
            var newArc = arc.ToPolyline();
            var startPoint = arc.GetByDegrees(start);
            var endPoint = arc.GetByDegrees(end);
            if (startPoint == null || endPoint == null)
            {
                throw XSException.Oh("坐标计算错误");
            }
            var list = newArc.GetSplitCurves(new Point3dCollection { startPoint.Value, endPoint.Value }).Cast<Curve>().ToList();
            return new Split3ArcModel(list[0], list[1], list[2]);
        }

        /// <summary>
        /// 获取弧上点的切线的垂线
        /// </summary>
        /// <param name="curves"></param>
        /// <param name="l"></param>
        /// <returns></returns>
        public static List<Line> GetArcPointVerticalLine(this List<Curve> curves, double l)
        { 
            var list=new List<Line>();

            for (int i = 0; i < curves.Count; i++)
            {
                var item = curves[i];
                if (i == 0)
                {
                    list.Add(item.VerticalLine(item.StartPoint, l));
                }
                list.Add(item.VerticalLine(item.EndPoint, l));
            }
            return list;
        }

        /// <summary>
        /// 将2个集合的 结束坐标合并  开始坐标在一点上，数量一直
        /// </summary>
        /// <param name="lines1"></param>
        /// <param name="lines2"></param>
        /// <returns></returns>
        public static List<Line> BothEndsMerge(this List<Line> lines1, List<Line> lines2 )
        { 

            var lines=new List<Line>();
            for (int i = 0; i < lines1.Count; i++)
            {
                var item1 = lines1[i];
                var item2 = lines2[i];  
                var line=new Line(item1.EndPoint,item2.EndPoint);
                lines.Add(line);
            }
            return lines;
        }


        public static Line GetLine(this Curve curve, Point3d point, double l)
        {
            var vt = curve.GetFirstDerivative(point).GetNormal();

            var start = point.Add(vt*-l);
            var end= point.Subtract(vt*l);

            return new Line(start, end);
        }



    }
}









